package cn.suimg.neo4j.util;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩包构建工具
 * @date 2020-12-26
 * @author SuimgPhilip (admin@suimg.cn)
 * @see ZipEntry, ZipOutputStream
 */
public class ZipBuildUtil {

    @Data
    private static class ZipFile {
        /**
         * 保存文件的名称
         */
        private String name;

        /**
         * 源文件名称
         */
        private File sourceFile;
    }


    /**
     * 保存文件的临时位置
     */
    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");

    /**
     * Logger
     */
    private static final Logger logger = LoggerFactory.getLogger(ZipBuildUtil.class);

    /**
     * 压缩整个文件夹
     * @param directory
     * @return
     */
    public static File compressFolder(File directory) throws IOException {
        if(!directory.isDirectory())
            throw new IOException("use compressFolder method only can compress Folder");
        long startTimestamp = System.currentTimeMillis();
        FileOutputStream fileOutputStream = null;
        ZipOutputStream zipOutputStream = null;
        File zipFile = new File(TEMP_DIR,directory.getName() + ".zip");
        try {
            fileOutputStream = new FileOutputStream(zipFile);
            zipOutputStream = new ZipOutputStream(fileOutputStream);
            compressFile(directory,zipOutputStream,directory.getName());
            logger.info("make zip successful!,use time {}ms",System.currentTimeMillis() - startTimestamp);
        } catch (IOException e) {
            logger.error("make zip file error:",e);
            throw e;
        }finally {
            if(zipOutputStream != null){
                try{
                    zipOutputStream.close();
                }catch (IOException e){
                    logger.error("close zip's stream failed",e);
                }
            }
            if(fileOutputStream != null){
                try{
                    fileOutputStream.close();
                }catch (IOException e){
                    logger.error("close file's stream failed",e);
                }
            }
        }
        return zipFile;
    }

    /**
     * 压缩文件
     * @param sourceFile
     * @param outputStream
     * @param name
     * @throws IOException
     */
    private static void compressFile(File sourceFile, ZipOutputStream outputStream,String name) throws IOException {
        if(sourceFile.isFile()){
            logger.info("add file [{}]",name);
            outputStream.putNextEntry(new ZipEntry(name));
            StreamUtils.copy(new FileInputStream(sourceFile),outputStream);
            outputStream.closeEntry();
        }else {
            File[] files = sourceFile.listFiles();
            if(files == null || files.length == 0 ){
                logger.info("add empty directory [{}]",name + "/");
                outputStream.putNextEntry(new ZipEntry(name + "/"));
                outputStream.closeEntry();
            }else {
                for (File file : files) {
                    compressFile(file,outputStream,name + "/" + file.getName());
                }
            }
        }
    }

    /**
     * 创建一个ZIP输出流
     * @param zipName 压缩文件名
     * @param files 文件列表
     * @return
     * @throws IOException
     */
    public static File buildZip(List<ZipFile> files) throws IOException {
        File zipFile = new File(TEMP_DIR, UUID.randomUUID().toString() + ".zip");

        FileOutputStream fileOutputStream = null;
        ZipOutputStream zipOutputStream =  null;

        try{
            fileOutputStream = new FileOutputStream(zipFile);
            zipOutputStream =  new ZipOutputStream(fileOutputStream);
            for(ZipFile fileItem : files){
                logger.info("add file [{}]",fileItem.getName());
                zipOutputStream.putNextEntry(new ZipEntry(fileItem.getName()));
                StreamUtils.copy(new FileInputStream(fileItem.getSourceFile()),zipOutputStream);
                zipOutputStream.closeEntry();
            }
        }catch (IOException e){
            logger.error("make zip file error",e);
            throw e;
        }finally {
            if(zipOutputStream != null)
                try{ zipOutputStream.close(); }catch (IOException ignored){}
            if(fileOutputStream != null)
                try{ fileOutputStream.close(); }catch (IOException ignored){}
        }

        return zipFile;
    }



}
